/*
 / _____)             _              | |
( (____  _____ ____ _| |_ _____  ____| |__
 \____ \| ___ |    (_   _) ___ |/ ___)  _ \
 _____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
    (C)2016 Semtech

Description: Handling of the node configuration protocol

License: Revised BSD License, see LICENSE.TXT file include in the project

Maintainer: Miguel Luis, Gregory Cristian and Matthieu Verdy
*/
#include "sx126x-hal.h"

#define BOARD_TCXO_WAKEUP_TIME  5 // no TCXO

#define RADIO_RESET_PORT                          GPIOA
#define RADIO_RESET_PIN							  GPIO_PIN_0

#define RADIO_NSS_PORT                            GPIOA
#define RADIO_NSS_PIN                             GPIO_PIN_4

#define RADIO_BUSY_PORT                           GPIOB
#define RADIO_BUSY_PIN                            GPIO_PIN_0

//#define RADIO_DIO_1_PORT                          GPIOB
//#define RADIO_DIO_1_PIN                           GPIO_PIN_4
//
//#define DEVICE_SEL_PORT                           GPIOA
//#define DEVICE_SEL_PIN                            GPIO_PIN_4

extern SPI_HandleTypeDef hspi1;
#define LORA_SPI			hspi1

/*!
 * \brief Helper macro to create Interrupt objects only if the pin name is
 *        different from NC
 */
#define CreateDioPin( pinName, dio )                 \
            if( pinName == NC )                      \
            {                                        \
                dio = NULL;                          \
            }                                        \
            else                                     \
            {                                        \
                dio = new InterruptIn( pinName );    \
            }

/*!
 * \brief Helper macro to avoid duplicating code for setting dio pins parameters
 */
#define DioAssignCallback( dio, pinMode, callback )                    \
            if( dio != NULL )                                          \
            {                                                          \
                dio->mode( pinMode );                                  \
                dio->rise( this, static_cast <Trigger>( callback ) );  \
            }

/*!
 * \brief Used to block execution waiting for low state on radio busy pin.
 */
#define WaitOnBusy( )             while( HAL_GPIO_ReadPin(RADIO_BUSY_PORT, RADIO_BUSY_PIN) == 1 );


/*!
 * \brief Used to block execution to give enough time to Busy to go up
 *        in order to respect Tsw, see datasheet ยง8.3.1
 */
#define WaitOnCounter( )          for( uint8_t counter = 0; counter < 15; counter++ ) \
                                  {  __NOP( ); }

                                  
// This code handles cases where assert_param is undefined
#ifndef assert_param
#define assert_param( ... )
#endif



void IoIrqInit( DioIrqHandler irqHandler )
{
//    DioAssignCallback( DIO1, PullNone, irqHandler );
}

void Reset( void )
{
//	GPIO_InitTypeDef initStruct = { 0 };
//
//	initStruct.Pin = RADIO_RESET_PIN;
//	initStruct.Mode = GPIO_MODE_OUTPUT_PP;
//	initStruct.Pull = GPIO_NOPULL;
//	initStruct.Speed = GPIO_SPEED_HIGH;

	HAL_GPIO_WritePin( RADIO_RESET_PORT, RADIO_RESET_PIN, 0 );

	// Wait 20 ms
	HAL_Delay( 20 );
	// Configure RESET as input
//	initStruct.Mode = GPIO_MODE_ANALOG;
//	HAL_GPIO_Init(GPIOB, &initStruct);
//	HAL_GPIO_WritePin( RADIO_RESET_PORT, RADIO_RESET_PIN, 0); // internal pull-up
	HAL_GPIO_WritePin( RADIO_RESET_PORT, RADIO_RESET_PIN, 1 );

	// Wait 10 ms
	HAL_Delay( 10 );
}

void Wakeup( void )
{
	uint8_t txData;

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

	txData = (uint8_t)RADIO_GET_STATUS;
	HAL_SPI_Transmit(&LORA_SPI, &txData, 1, HAL_MAX_DELAY);

	txData = (uint8_t)0;
	HAL_SPI_Transmit(&LORA_SPI, &txData, 1, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );

    // Wait for chip to be ready.
    WaitOnBusy( );
}

void WriteCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
{
	uint8_t txData;

#ifdef ADV_DEBUG
    printf("cmd: 0x%02x", command );
    for( uint8_t i = 0; i < size; i++ )
    {
        printf("-%02x", buffer[i] );
    }
    printf("\n\r");
#endif
    
    WaitOnBusy( );

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

	txData = (uint8_t)command;
	HAL_SPI_Transmit(&LORA_SPI, &txData, 1, HAL_MAX_DELAY);

	HAL_SPI_Transmit(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );

    WaitOnCounter( );
}

void ReadCommand( RadioCommands_t command, uint8_t *buffer, uint16_t size )
{
    uint8_t status = 0;
    uint8_t txData;

    WaitOnBusy( );

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

	txData = (uint8_t)command;
	HAL_SPI_Transmit(&LORA_SPI, &txData, 1, HAL_MAX_DELAY);

	HAL_SPI_Transmit(&LORA_SPI, &status, 1, HAL_MAX_DELAY);

    HAL_SPI_Receive(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );
}

void WriteRegister( uint16_t address, uint8_t *buffer, uint16_t size )
{
	uint8_t	txData[3];

    WaitOnBusy( );

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

	txData[0] = (uint8_t)RADIO_WRITE_REGISTER;
	txData[1] = (uint8_t)(( address & 0xFF00 ) >> 8);
	txData[2] = (uint8_t)(address & 0x00FF );
	HAL_SPI_Transmit(&LORA_SPI, txData, 3, HAL_MAX_DELAY);

	HAL_SPI_Transmit(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );
}

void WriteReg( uint16_t address, uint8_t value )
{
    WriteRegister( address, &value, 1 );
}

void ReadRegister( uint16_t address, uint8_t *buffer, uint16_t size )
{
	uint8_t	txData[4];

    WaitOnBusy( );

    //NSS = 0;
     HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

 	txData[0] = (uint8_t)RADIO_READ_REGISTER;
 	txData[1] = (uint8_t)(( address & 0xFF00) >> 8 );
 	txData[2] = (uint8_t)(address & 0x00FF);
 	txData[0] = (uint8_t)0;
 	HAL_SPI_Transmit(&LORA_SPI, txData, 4, HAL_MAX_DELAY);

 	HAL_SPI_Receive(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

     //NSS = 1;
     HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );
}

uint8_t ReadReg( uint16_t address )
{
    uint8_t data;

    ReadRegister( address, &data, 1 );
    return data;
}

void WriteBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
{
	uint8_t	txData[2];

    WaitOnBusy( );

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

    txData[0] = RADIO_WRITE_BUFFER;
    txData[1] = offset;
    HAL_SPI_Transmit(&LORA_SPI, txData, 2, HAL_MAX_DELAY);

    HAL_SPI_Transmit(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );
}

void ReadBuffer( uint8_t offset, uint8_t *buffer, uint8_t size )
{
	uint8_t	txData[3];

    WaitOnBusy( );

    //NSS = 0;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 0 );

    txData[0] = RADIO_READ_BUFFER;
    txData[1] = offset;
    txData[2] = 0;
    HAL_SPI_Transmit(&LORA_SPI, txData, 3, HAL_MAX_DELAY);

    HAL_SPI_Receive(&LORA_SPI, buffer, size, HAL_MAX_DELAY);

    //NSS = 1;
    HAL_GPIO_WritePin( RADIO_NSS_PORT, RADIO_NSS_PIN, 1 );
}

uint8_t GetDioStatus( void )
{
	// TODO:
	return 0;
//    return ( *DIO3 << 3 ) | ( *DIO2 << 2 ) | ( *DIO1 << 1 ) | ( BUSY << 0 );
}

uint8_t GetDeviceType( void )
{

	return( SX1262 );
}

